package main

import (
	"encoding/base64"
	"fmt"
	"io/ioutil"
)

// https://refactoringguru.cn/design-patterns/decorator

type DataSource interface {
	Write(string)
	Read() string
}

////////////

type FileDataSource struct {
	filename string
}

func NewFileDataSource(filename string) *FileDataSource {
	return &FileDataSource{filename: filename}
}

func (f *FileDataSource) Write(s string) {
	ioutil.WriteFile(f.filename, []byte(s), 0644)
}

func (f *FileDataSource) Read() string {
	b, err := ioutil.ReadFile(f.filename)
	if err != nil {
		panic(err)
	}
	return string(b)
}

////////////

type Base64Decorator struct {
	wrappee DataSource
}

func NewBase64Decorator(wrappee DataSource) *Base64Decorator {
	return &Base64Decorator{wrappee: wrappee}
}

func (f *Base64Decorator) Write(s string) {
	s = base64.StdEncoding.EncodeToString([]byte(s))
	fmt.Println("write base64:", s)
	f.wrappee.Write(s)
}

func (f *Base64Decorator) Read() string {
	s := f.wrappee.Read()
	fmt.Println("read base64:", s)
	b, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return string(b)
}

func main() {
	var source DataSource

	// 组合的逻辑放在 FileDataSource 之外进行
	// 避免 FileDataSource 和 Decorator 耦合太深
	source = NewFileDataSource("data")
	source = NewBase64Decorator(source)
	source.Write("decorator")
	fmt.Println(source.Read())
}
